package cn.baiy;
  //游戏框类

import javax.swing.*;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.*;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class World extends JPanel{//整个游戏世界

    public static final int WIDTH = 641;//窗口的宽
    public static final int HEIGHT = 479;//窗口的高

    public static final int RUNNING = 0;//运行状态
    public static final int PAUSE = 1;//暂停状态
    public static final int GAME_OVER = 2;//游戏结束
    private int state = RUNNING;//当前状态（默认为运行状态）

    private BattleShip ship = new BattleShip();//战船
    private SeaObject[] submarines = {};//三种潜艇数组
    private Mine[] mines = {};//水雷数组
    private Bomb[] bombs = {};//炸弹数组

    private SeaObject nextSubmarine(){//生成三种潜艇对象
        Random rand = new Random();
        int type = rand.nextInt(28);
        if (type < 8){
            return new MineSubmarine();
        }else if (type < 18){
            return new ObserveSubmarine();
        }else {
            return new TorpedoSubmarine();
        }
    }

    private int subEnterIndex = 0;//潜艇入场计数
    private void submarineEnterAction(){//每10毫秒走一次
        subEnterIndex++;
        if (subEnterIndex % 40 == 0){
            SeaObject obj = nextSubmarine();//获得潜艇对象
            submarines = Arrays.copyOf(submarines,submarines.length+1);//扩容
            submarines[submarines.length-1] = obj;//放到数组的最后一个元素上
        }
    }

    private int mineEnterAction = 0;//水雷入场计数
    private void mineEnterAction(){
        mineEnterAction++;
        if (mineEnterAction % 100 == 0){//1秒走一次
            for (int i = 0; i < submarines.length; i++) {//遍历所有潜艇
                if (submarines[i] instanceof MineSubmarine){//若潜艇为水雷潜艇
                    MineSubmarine ms = (MineSubmarine) submarines[i];//将潜艇强转为水雷潜艇
                    Mine obj = ms.shootMine();//获得水雷对象
                    mines = Arrays.copyOf(mines,mines.length+1);//扩容
                    mines[mines.length-1] = obj;//放在最后
                }
            }
        }
    }

    private void moveAction(){//海洋对象移动
        for (int i = 0; i < submarines.length; i++) {//遍历所有潜艇
            submarines[i].move();//潜艇移动
        }
        for (int i = 0; i < bombs.length; i++) {
            bombs[i].move();
        }
        for (int i = 0; i < mines.length; i++) {
            mines[i].move();
        }
    }

    private void outBoundsAction(){//删除越界的海洋对象-----避免内存泄漏
        for (int i = 0; i < submarines.length; i++) {//遍历所有潜艇
            if (submarines[i].isOutOfBounds() || submarines[i].isDead()){//越界的、或者死了的
                submarines[i] = submarines[submarines.length-1];//将越界潜艇替换为最后一个元素
                submarines = Arrays.copyOf(submarines,submarines.length-1);//缩容
            }
        }
        for (int i = 0; i < mines.length; i++) {
            if (mines[i].isOutOfBounds() || mines[i].isDead()){
                mines[i] = mines[mines.length-1];
                mines = Arrays.copyOf(mines,mines.length-1);
            }
        }
        for (int i = 0; i < bombs.length; i++) {
            if (bombs[i].isOutOfBounds() || bombs[i].isDead()){
                bombs[i] = bombs[bombs.length-1];
                bombs = Arrays.copyOf(bombs,bombs.length-1);
            }
        }
    }

    private int score = 0;//玩家得分
    private void bombBangAction(){
        for (int i = 0; i < bombs.length; i++) {
            Bomb b = bombs[i];//获得炸弹
            for (int j = 0; j < submarines.length; j++) {
                SeaObject s = submarines[j];//获得三种潜艇
                if (b.isLive() && s.isLive() && s.isHit(b)){//炸弹活着的、潜艇活着的、并且还撞上了
                    b.goDead();//炸弹去死
                    s.goDead();//潜艇去死
                    if (s instanceof EnemyScore){//若被撞对象务分
                        EnemyScore es = (EnemyScore) s;//将被撞对象强转为得分接口
                        score += es.getScore();//玩家得分
                    }
                    if (s instanceof EnemyLife){//若被撞对象为命
                        EnemyLife el = (EnemyLife) s;//将被撞对象强转为得命接口
                        int num = el.getLife();//获得命数
                        ship.addLife(num);//战舰加命
                    }
                }
            }
        }
    }


    private   void mineBangAction(){//水雷与战舰的碰撞
        for (int i = 0; i < mines.length; i++) {
            Mine m = mines[i];//获得每个水雷
            if (m.isLive() && ship.isLive() && ship.isHit(m)){//都活着还撞上了
                m.goDead();//水雷去死
                ship.subtractLife();//战舰减命
            }
        }
    }

    private void cheakGameOverAction(){//检测游戏结束
        if (ship.getLife() <= 0){
            state =GAME_OVER;
        }
    }

    private  void loadGame(){
        File file = new File("save.sav");
        if (file.exists()){
            int r = JOptionPane.showConfirmDialog(
                    this,"是否读档"
            );
            if (r == JOptionPane.YES_OPTION){
                try {
                    FileInputStream fis = new FileInputStream(file);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    SaveInfo saveInfo = (SaveInfo) ois.readObject();
                    ois.close();

                    ship = saveInfo.getShip();
                    submarines = saveInfo.getSubmarines();
                    mines = saveInfo.getMines();
                    bombs = saveInfo.getBombs();
                    subEnterIndex = saveInfo.getSubEnterIndex();
                    mineEnterAction = saveInfo.getMineEnterAction();
                    score = saveInfo.getScore();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private void action(){//启动程序的执行
        loadGame();//读取游戏存档
        KeyAdapter k = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {//按下时（上升沿）
                if (e.getKeyCode() == KeyEvent.VK_P){//若按P键
                    state = PAUSE;
                    int r = JOptionPane.showConfirmDialog(
                            World.this,"保存游戏吗？");
                    if (r == JOptionPane.YES_OPTION){
                        SaveInfo saveInfo = new SaveInfo(ship,
                                submarines,mines,bombs,subEnterIndex,
                                mineEnterAction,score);
                    try {
                        FileOutputStream fos = new FileOutputStream("save.sav");
                        ObjectOutputStream oos = new ObjectOutputStream(fos);
                        oos.writeObject(saveInfo);
                        oos.close();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                    }
                    state = RUNNING;
                                     /*if (state == RUNNING){//运行状态时修改为暂停状态
                                     state = PAUSE;
                                     }else if (state == PAUSE){//暂停状态时修改为运行状态
                                     state = RUNNING;
                                     }*/
                }
                if (state != RUNNING){//若当前状态不是运行状态
                    return;//则结束事件处理
                }
                if (e.getKeyCode() == KeyEvent.VK_SPACE){//按空格健
                    Bomb obj = ship.shootBomb();//获得炸弹对象
                    bombs = Arrays.copyOf(bombs,bombs.length+1);//扩容
                    bombs[bombs.length-1] = obj;//放在最后
                }
                if (e.getKeyCode() == KeyEvent.VK_LEFT){//按左移键
                    ship.moveLeft();//战舰左移
                }
                if (e.getKeyCode() == KeyEvent.VK_RIGHT){//按右移键
                    ship.moveRight();
                }
            }
        };
        this.addKeyListener(k);

        Timer timer = new Timer();//定时器对象
        int interval = 10;//定时间隔（以豪秒为单位）
        timer.schedule(new TimerTask() {
            @Override
            public void run() {//定时要干的事
                if (state == RUNNING){//仅在运行状态时执行
                    submarineEnterAction();//三种潜艇
                    mineEnterAction();//水雷入场
                    moveAction();//海洋对象移动
                    outBoundsAction();//删除越界的海洋对象
                    bombBangAction();//炸弹与潜艇相撞
                    mineBangAction();//水雷与战舰的碰撞
                    cheakGameOverAction();//检测游戏结束
                }
                repaint();//重写调用paint()方法
            }
        }, interval, interval);//日程表
    }

    @Override
    public void paint(Graphics g){//重写JPanel类中的paint()方法、画东西就要重写
        Images.sea.paintIcon(null,g,0,0);//画海洋图
        ship.paintImage(g);//画战船
        for (int i=0;i<submarines.length;i++){
            submarines[i].paintImage(g);//画所有潜艇
        }
        for (int i=0;i<mines.length;i++){
            mines[i].paintImage(g);
        }
        for (int i=0;i<bombs.length;i++){
            bombs[i].paintImage(g);
        }

        g.drawString("SCORE："+score,200,50);//画分
        g.drawString("LIFE："+ship.getLife(),400,50);//画命

        if (state == GAME_OVER){//若当前状态为游戏结束状态
            Images.gameover.paintIcon(null,g,0,0);//画游戏结束图
        }

        g.drawString("发射炸弹按空格键、移动按左右健、暂停按P键（再按P键继续）",10,20);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH+16, HEIGHT+39);  //641、479是海洋图的宽、高 ，16、39是游戏框在win10系统中左右、上边框的边距。
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);//自动调用paint()方法

        world.action();//调用上面的action()方法

    }
}
